package com.yf.cmw.presenter;


import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.FileObserver;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.annotation.NonNull;
import android.util.Log;
import android.widget.Toast;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.base.common.bean.AppVersionResult;
import com.base.common.db.model.MachineCacheInfo;
import com.base.common.http.handler.CompleteCallback;
import com.base.common.http.handler.HttpBusinessCallback;
import com.base.common.http.model.DownLoadModel;
import com.base.common.http.model.HttpConfigModel;
import com.base.common.http.server.MicroHttpServer;
import com.base.common.listener.SDCardFileObserver;
import com.base.common.network.JsonHelper;
import com.base.common.util.AppTools;
import com.base.common.util.Base64Utils;
import com.base.common.util.CommonUtil;
import com.base.common.util.DownloadUtil;
import com.base.common.util.EnvironmentShare;
import com.base.common.util.FastJsonUtil;
import com.base.common.util.FileUtil;
import com.base.common.util.HexUtils;
import com.base.common.util.HttpUtil;
import com.base.common.util.RsaUtils;
import com.base.common.util.SharedPreferencesUtil;
import com.base.common.util.ShellUtils;
import com.base.common.util.StringHandler;
import com.base.common.util.StringUtils;
import com.base.common.util.ToastAlert;
import com.base.common.util.date.DateUtil;
import com.base.common.util.log.LogUtil;
import com.yf.cmw.constant.BussConstant;
import com.yf.cmw.constant.UrlConstantAPI;
import com.yf.cmw.dao.buss.DownloadLogDao;
import com.yf.cmw.dao.buss.MachineLogDao;
import com.yf.cmw.entity.DownloadLogEntity;
import com.yf.cmw.entity.DownloadLogResult;
import com.yf.cmw.entity.MachineLogEntity;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

import static com.yf.cmw.constant.BussConstant.ACTION_AD_ADDED;
import static com.yf.cmw.constant.BussConstant.TEMP_FILE_PREFIX;

public class MainPresenter {
    static final String TAG = "MainPresenter";

    Context mContext;

    AsyncCallback callback;

    public int bussFlag = -1; //无业务标识 ，由调用方传入

    SharedPreferencesUtil sharedPreferencesUtil;
    MachineCacheInfo machineCacheInfo;
    DownloadLogDao downloadLogDao = null;
    MachineLogDao mlogDao = null;
    HandlerThread handlerThread;
    Handler handler;

    PublicKey publicKey;

    static final int MINUTES = 20; //分钟
    static final long TIMEOUT = 1000*60*MINUTES;

    public MainPresenter(Context mContext) {
        this(mContext, null);
    }


    public MainPresenter(Context mContext,AsyncCallback callback) {
        this.mContext = mContext;
        this.callback = callback;
        ToastAlert.init(mContext);
        sharedPreferencesUtil = SharedPreferencesUtil.getInstance(this.mContext);
        machineCacheInfo = MachineCacheInfo.getInstance(this.mContext);
        downloadLogDao = new DownloadLogDao(mContext);
        mlogDao = new MachineLogDao(mContext);
        try{
            publicKey = RsaUtils.getPublicKey(mContext.getAssets().open("rsa.pub"));
//        PrivateKey privateKey = RsaUtils.getPrivateKey(mContext.getAssets().open("rsa.pri"));
        }catch (Exception ex){
            ex.printStackTrace();
        }
        HttpUtil.setContext(mContext);
        initHandler();
    }

    void initHandler() {
        handlerThread = new HandlerThread("TaskService-task");
        handlerThread.start();
        handler = new Handler(handlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 1:
                        break;
                }
            }
        };
    }

    private String getUrl(){
        if (null == machineCacheInfo) {
            machineCacheInfo = MachineCacheInfo.getInstance(mContext);
        }
        if(StringUtils.isEmpty(machineCacheInfo.getServerUrl())){ //当缓存中没有写入 servler Url 时，就用常量中定义的服务器地址
            machineCacheInfo.setServerUrl(BussConstant.getUrl());
            machineCacheInfo.writeToCache();
        }
        String url =  machineCacheInfo.getServerUrl();
        Log.i(TAG,"getUrl="+url);
        return url;
    }


    @Deprecated
    public static void writeLogRecord(String url) {
        if(1==1) return;
        String mADPlayRecordFileDir = BussConstant.LOG_ADPATH;
        if (!FileUtil.isFileExist(mADPlayRecordFileDir)) {
            FileUtil.creatSDDir(mADPlayRecordFileDir);
        }

        String filePath = mADPlayRecordFileDir + "YFSpsApp" +"_" + DateUtil.getCurrentDate() + ".txt";
        String mPlayStartTime = DateUtil.getCurrentDateTime();
        String content = mPlayStartTime + " " + DateUtil.getCurrentDateSuffix() + " " + url + "\n";

        FileUtil.writeToFile(new File(filePath),content,true);

    }

    /**
     * 服务器联网测试
     */
    public void test(String url){
        if(StringUtils.isEmpty(url)) url = getUrl() + UrlConstantAPI.SERVIER_TEST;
        Log.i(TAG,"test.url="+url);
        final String server_url = url;
        Map<String, String> params = new HashMap<String, String>();
        HttpUtil.get(url, params, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.i(TAG,"onFailure...");
                e.printStackTrace();
                String msg = e.getMessage();
                Log.i(TAG, msg);
                outFalure(msg,server_url);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                Log.i(TAG,"onResponse...");
                Log.i(TAG,result);
                JSONObject resultJson = FastJsonUtil.convertStrToJSONObj(result);
                outSuccess(resultJson,server_url);
            }
        });
    }

    private <T> void outSuccess(T resultData, String url){
        JSONObject result = new JSONObject();
        result.put("success", true);
        result.put("msg", "ok");
        result.put(BussConstant.SERVER_URL_KEY, url);
        result.put("datas", resultData);
        if(null != callback) callback.success(bussFlag, result);
    }


    private void outSuccess(JSONObject resultJson){
        if(null != callback) callback.success(bussFlag, resultJson);
    }

    private void outFalure(String msg, String url){
        JSONObject result = new JSONObject();
        result.put("success", false);
        result.put("msg", msg);
        result.put(BussConstant.SERVER_URL_KEY, url);
        if(null != callback) callback.failure(bussFlag, result);
    }

    /**
     * 从服务器拉取最新配置
     */
    public void getMachineCfg() {
        getMachineCfg(null);
    }

    /**
     * 获取文件监控对象
     * @return
     */
    public synchronized SDCardFileObserver getAdSourceFileObserver(){
        String adPath = machineCacheInfo.getAdPath();
        if(StringUtils.isEmpty(adPath)) adPath = BussConstant.DEFAULT_ADPATH;
        return new SDCardFileObserver(adPath, new SDCardFileObserver.FileChangeNotify() {
            @Override
            public void notify(int action, String path) {
                Log.i(TAG, String.format("getAdSourceFileObserver. action = %d, path = %s", action, path));
                int cmd = (FileObserver.CREATE ==  action) ? BussConstant.CMD_AD_ADD : BussConstant.CMD_AD_DEL;
                notifyADAction(cmd);
            }
        });
    }


    public void startHttpServer(){
        String homeDir = machineCacheInfo.getAdPath();
        HttpConfigModel httpConfig = new HttpConfigModel(homeDir);
        boolean isRunning = MicroHttpServer.getRunning();
        if(isRunning){
            int httpPort = httpConfig.getHttpPort();
            int socketPort = httpConfig.getSocketPort();
            Log.i(TAG,String.format("MicroHttpServer is running at http-port : %d, socket-port:",httpPort,socketPort));
            return;
        }
        CompleteCallback completeCallback = new CompleteCallback() {
            @Override
            public void completed(DownLoadModel downLoadModel) {
                DownloadLogEntity downloadLog = downloadLogDao.save(downLoadModel);
                downloadLog.setXstatus(BussConstant.XSTATUS_2);
                downloadLog.setSstatus(BussConstant.SSTATUS_2);
                downloadLogDao.update(downloadLog);
                notifyADAction(BussConstant.ACTION_AD_ADDED,downloadLog, BussConstant.CMD_AD_ADD);
            }
        };
        MicroHttpServer.start(httpConfig, completeCallback, httpBusinessCallback);
    }

    public void stopHttpServer(){
        MicroHttpServer.stop();
    }

    /**
     * 从服务器拉取最新配置
     */
    public void getMachineCfg(String url) {
       if(StringUtils.isEmpty(url)) url = getUrl() + UrlConstantAPI.MCONFIG_PULL;
        final String server_url = url;
        writeLogRecord("[getMachineCfg Started; URL = "+url);
        Map<String, String> params = new HashMap<String, String>();
        HttpUtil.get(url, params, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                String msg = e.getMessage();
                String errMsg = "[getMachineCfg]从服务器拉取最新配置出现错误，原因："+msg;
                Log.e(TAG, errMsg);
                writeLogRecord(errMsg);
                outFalure(msg,server_url);
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String jsonStr = response.body().string();
                writeLogRecord("[getMachineCfg] "+jsonStr);
                JSONObject jsonResult = FastJsonUtil.convertStrToJSONObj(jsonStr);
                if(null != jsonResult && jsonResult.getBoolean("success")){
                    JSONObject data = jsonResult.getJSONObject("datas");
                    if(null != data && data.size() > 0){
                        //1.save machine cfg to cache
                        String apiUrl = data.getString("serverUrl");
                        String safeCode = data.getString("safeCode");
                        Integer cfgVersion = data.getInteger("cfgVersion");
                        String adPath = data.getString("adPath");
                        Integer minutes = data.getInteger("minutes");
                        if(StringUtils.isEmpty(apiUrl)) apiUrl = "";
                        if(StringUtils.isEmpty(safeCode)) safeCode = "";
                        if(null == cfgVersion) cfgVersion = 1;
                        if(StringUtils.isEmpty(adPath)) adPath = "";
                        if (null == minutes || minutes.intValue() < 1) {
                            minutes = 1;
                        }
                        long appVersion = AppTools.getVersionCode(mContext);

                        machineCacheInfo.setServerUrl(apiUrl);
                        machineCacheInfo.setAdPath(adPath);
                        machineCacheInfo.setMinutes(minutes);
                        machineCacheInfo.setAppVersion(appVersion+"");
                        machineCacheInfo.setCfgVersion(cfgVersion + "");
                        machineCacheInfo.setSafeCode(safeCode);
                        machineCacheInfo.writeToCache();
                    }else{
                        Log.e(TAG,"从服务端未能获取到App配置参数信息，请检查服务端是否有进行相关配置！");
                    }
                }else{
                    String msg = jsonResult.getString("msg");
                    Log.e(TAG,"从服务端获取到App配置参数信息失败，原因："+msg+"！");
                }
                outSuccess(machineCacheInfo,server_url);
            }
        });
        writeLogRecord("[getMachineCfg END; URL = "+url);
    }

    /**
     * 获取轮循时间
     * @return
     */
    public int getRoundTime(){
        if (null == machineCacheInfo) {
            machineCacheInfo = MachineCacheInfo.getInstance(mContext);
        }
        Integer minutes = machineCacheInfo.getMinutes();
        int roundTime = BussConstant.TIME_INTERVAL;
        if(null != minutes){
            roundTime = minutes * 60 * 1000;
        }
        Double randomVal = Math.random()*10000;
        int _roundTime = roundTime + randomVal.intValue();
        Log.i(TAG,String.format( "getRoundTime[roundTime:%d,randomVal:%f,_roundTime:%d]",roundTime,randomVal,_roundTime));
        return _roundTime;
    }

    /**
     * 获取机器串码
     * @return
     */
    public String getMcode(){
        if (null == machineCacheInfo) {
            machineCacheInfo = MachineCacheInfo.getInstance(mContext);
        }
        if(StringUtils.isEmpty(machineCacheInfo.getMcode())){ //当缓存中没有写入 servler Url 时，就用常量中定义的服务器地址
            String code = AppTools.getDeviceId(mContext);
            code = Base64Utils.getBase64(code);
            code = code.replace("=", "").toUpperCase();
            machineCacheInfo.setMcode(code);
            machineCacheInfo.writeToCache();
        }
        return machineCacheInfo.getMcode();
    }


    public void delLogs() {
        mlogDao.delete(null, null);
        downloadLogDao.delete(null, null);
        List<MachineLogEntity> mlogList = mlogDao.getList(null, null);
        List<DownloadLogEntity> downLogList = downloadLogDao.getList(null, null);
        int mlogCount = 0;
        int downLogCount = 0;
        if (null != mlogList && mlogList.size() > 0) {
            mlogCount = mlogList.size();
        }
        if (null != downLogList && downLogList.size() > 0) {
            downLogCount = downLogList.size();
        }
        String msg = "删除后还有“" + mlogCount + "”条机器日志，“" + downLogCount + "”条下载日志";
        Toast.makeText(mContext, msg, Toast.LENGTH_LONG).show();
    }

    /**
     * 发送机器串码
     */
    public void sendMcode(String url, String mcode) {
        String imei = (StringUtils.isEmpty(mcode)) ? getMcode() : mcode;
        if(StringUtils.isEmpty(url))  url = getUrl() + UrlConstantAPI.UNIME_SAVE;
        final String server_url = url;
        Map<String, String> params = new HashMap<String, String>();
        params.put("imei", imei);
        HttpUtil.get(url, params, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                String msg = e.getMessage();
                Log.e(TAG, msg);
                outFalure(msg,server_url);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.i(TAG,"sendMcode.onResponse...");
                String result = response.body().string();
                Log.i(TAG,result);
                JSONObject resultJson = FastJsonUtil.convertStrToJSONObj(result);
                outSuccess(resultJson, server_url);
            }
        });
    }

    private boolean isSameFile(String[] fileNames, String sourceFileName){
        boolean flag = false;
        String filePrefix = sourceFileName.substring(0,sourceFileName.lastIndexOf("."));
        for(String fileName : fileNames){
            String tmpFilePrefix = "._"+filePrefix;
            if(fileName.indexOf(tmpFilePrefix) != -1) continue; //跳过临时文件,当第二次复制文件时，会留下 ._蚂蚁搬家_2.mp4 的临时文件要排除掉
            if(fileName.indexOf(filePrefix) != -1) return true;
        }
        return flag;
    }

    /**
     * 复制U盘文件到机器广告目录里 ADSources
     * @param usbPath
     */
    public String copyUsbADSToMachine(String usbPath){
        String machineAdPath = machineCacheInfo.getAdPath();
        File machieAdDirs = new File(machineAdPath);
        final String[] machineFileNames = machieAdDirs.list();
        String adDir = usbPath + BussConstant.USB_ADPATH;
        File adDirFile = new File(adDir);
        if(!adDirFile.exists()){
            //ToastAlert.showMsg();
            String msg = String.format("U盘中没有广告文件夹%s,无法复制广告文件，请检查!", adDir);
            Log.e(TAG, msg);
            return msg;
        }
        File[] adFiles = null;
        if(null == machineFileNames || machineFileNames.length == 0){
            adFiles = adDirFile.listFiles(new FilenameFilter() {
                @Override
                public boolean accept(File dir, String name) {
                    name = name.toLowerCase();
                    boolean flag = (name.endsWith(".mp4") || name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".txt"));
                    if(flag && name.startsWith("._")) return false; //同名临时文件跳过
                    return flag;
                }
            });
        }else{
            adFiles = adDirFile.listFiles(new FilenameFilter() {
                @Override
                public boolean accept(File dir, String name) {
                    name = name.toLowerCase();
                    if(isSameFile(machineFileNames, name)) return false;
                    boolean flag = (name.endsWith(".mp4") || name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".txt"));
                    if(flag && name.startsWith("._")) return false; //同名临时文件跳过
                    return flag;
                }
            });
        }
        String _msg = null;
        if(null == adFiles || adFiles.length == 0){
            //ToastAlert.showMsg();
            _msg = String.format("U盘%s文件夹中没有广告文件,请检查广告文件是否放在%s文件夹下面", adDir,adDir);
            Log.e(TAG, _msg);
            return _msg;
        }

        int fileCout = 0;
        if(null != adFiles && adFiles.length > 0){
            fileCout = adFiles.length;
        }

        if(fileCout == 0) return _msg;
        Log.i(TAG, String.format("U盘%s文件夹中共有%s个广告文件准备复制中...", adDir,fileCout+""));

        int num = 0;
        for(File adFile : adFiles){
            num++;
            String fileName = adFile.getName();
            String adAbsFileName = adFile.getAbsolutePath();
            FileInputStream fileInputStream = null;
            try {
                String msg = String.format("共%d文件,开始从U盘中复制第%d个文件：%s",fileCout, num,adAbsFileName);
                Log.i(TAG, msg);
                //ToastAlert.showMsg(msg);
                fileInputStream = new FileInputStream(adFile);
                String filePrefix = fileName.substring(0,fileName.lastIndexOf("."));
                String newFileName = fileName.replace(filePrefix,filePrefix+"_2");//_2 代表是本地文件
                com.base.common.util.file.FileUtil.writeToSdcard(fileInputStream,machineAdPath,newFileName);
                msg = String.format("共%d文件,已完成从U盘中复制第%d个文件：%s",fileCout, num,adAbsFileName);
                Log.i(TAG, msg);
                //ToastAlert.showMsg(msg);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }finally {
                if(null != fileInputStream) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        String msg = String.format("U盘%s文件夹中的%s个广告文件全部复制完成", adDir,fileCout+"");
      // ToastAlert.showMsg(msg);
        Log.i(TAG, msg);
        notifyADAction(BussConstant.ACTION_AD_ADDED, null, BussConstant.CMD_AD_ADD);
        loadLocalFilesToJsonFile();
        return msg;
    }

    /**
     * 更新资源状态
     *
     * @param sourceId
     * @param xstatus
     */
    private void updateSourceStatus(String sourceId, int xstatus) {
        String url = getUrl() + UrlConstantAPI.UPDATE_SOURCE_STATUS;
        final String server_url = url;
        String xstatusMsg = "未知状态";
        switch (xstatus) {
            case BussConstant.SSTATUS_2: {
                xstatusMsg = "上刊";
                break;
            }
            case BussConstant.SSTATUS_3: {
                xstatusMsg = "下架";
                break;
            }
        }

        final String _xstatusMsg = xstatusMsg;
        Callback cb = new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                LogUtil.i(TAG, "updateSourceStatus.onFailure..." + e.getMessage());
                String msg = e.getMessage();
                outFalure(msg,server_url);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.i(TAG,"updateSourceStatus.onResponse...");
                String result = response.body().string();
                Log.i(TAG,result);
                JSONObject resultJson = FastJsonUtil.convertStrToJSONObj(result);
                Boolean success = resultJson.getBoolean("success");
                String msg = resultJson.getString("msg");
                if (null == success || !success) {
                    LogUtil.i(TAG, _xstatusMsg + "失败，原因：" + msg);
                } else {

                }
                outSuccess(resultJson,server_url);
            }
        };

        final Map<String, String> params = getBasePars();
        params.put("sourceId", sourceId + "");
        params.put("xstatus", xstatus + "");
        HttpUtil.put(url, params, cb);
    }


    private String getScommandDes(Integer scommand) {

        //1：心跳检查,2：下载视频,3：删除广告,4:重启机器,5:软件升级

        String scommandDes = "心跳检查";
        if (null != scommand) {
            switch (scommand.intValue()) {
                case BussConstant.SCOMMAND_1:
                    scommandDes = "心跳检查";
                    break;
                case BussConstant.SCOMMAND_2:
                    scommandDes = "期刊下载";
                    break;
                case BussConstant.SCOMMAND_3:
                    scommandDes = "下架期刊";
                    break;
                case BussConstant.SCOMMAND_4:
                    scommandDes = "报送日志";
                    break;
                case BussConstant.SCOMMAND_5:
                    scommandDes = "重启系统";
                    break;
                case BussConstant.SCOMMAND_6:
                    scommandDes = "APP升级";
                    break;
                case BussConstant.SCOMMAND_7:
                    scommandDes = "播放记录报送";
                    break;
                case BussConstant.SCOMMAND_8:
                    scommandDes = "截图文件报送";
                    break;
                case BussConstant.SCOMMAND_9:
                    scommandDes = "议峰智播日志报送";
                    break;
                case BussConstant.SCOMMAND_10:
                    scommandDes = "议峰光传日志报送";
                    break;
                default:
                    break;
            }
        }
        return scommandDes;
    }

    /**
     * 报送日志
     */
    public void parseMachineLog(DownloadLogResult downloadLogResult) {
        String startDate = downloadLogResult.getStartDate();
        String endDate = downloadLogResult.getEndDate();

        if (!StringHandler.isValidStr(startDate)) {
            startDate = DateUtil.getCurrentDateTime();
        }
        if (!StringHandler.isValidStr(endDate)) {
            endDate = DateUtil.getPreDateStr("dd", startDate, -1);
        }
        List<MachineLogEntity> mlogList = mlogDao.getList(startDate, endDate);
        Map<String, String> pars = getBasePars();
        pars.put("scommand", BussConstant.SCOMMAND_4 + "");
        pars.put("logType", "1"); //机器日志
        StringBuilder sbLog = new StringBuilder();
        sbLog.append("===[" + startDate + " 至 " + endDate + "]机器日志===\n");
        if (null == mlogList || mlogList.size() == 0) {
            sbLog.append("没有产生机器日志...");
        } else {
            for (MachineLogEntity mlog : mlogList) {
                Integer scommand = mlog.getScommand();
                String createTime = mlog.getCreateTime();
                String modifyTime = mlog.getModifyTime();
                String remark = mlog.getRemark();
                String scommandDes = getScommandDes(scommand);
                sbLog.append(scommandDes).append(";").append(remark)
                        .append(";").append(createTime)
                        .append(";").append(modifyTime).append("\n");
            }
        }
        pars.put("content", sbLog.toString());
        postMachineLog(pars);


        //***------ 下载日志报送 ------***//
        List<DownloadLogEntity> downLoadLogs = downloadLogDao.getList(startDate, endDate);
        sbLog = new StringBuilder();
        sbLog.append("===[" + startDate + " 至 " + endDate + "]机器日志===\n");
        if (null == mlogList || mlogList.size() == 0) {
            sbLog.append("没有产生下载日志...");
        } else {
            for (DownloadLogEntity downloadLog : downLoadLogs) {
                Integer btype = downloadLog.getBtype();
                String fname = downloadLog.getFname();
                String durl = downloadLog.getDurl();
                String lpath = downloadLog.getLpath();
                String createTime = downloadLog.getCreateTime();
                String endTime = downloadLog.getEndTime();
                String finishTime = downloadLog.getFinishTime();
                Integer sstatus = downloadLog.getSstatus();
                Integer xstatus = downloadLog.getXstatus();
                if (null == btype) btype = BussConstant.BTYPE_1;
                String btypeName = "广告文件";
                if (btype.intValue() == BussConstant.BTYPE_2) {
                    btypeName = "软件升级文件";
                }
                String sstatusName = "上刊中";
                if (null != sstatus) {
                    switch (sstatus.intValue()) {
                        case BussConstant.SSTATUS_1:
                            sstatusName = "上刊中";
                            break;
                        case BussConstant.SSTATUS_2:
                            sstatusName = "已上刊";
                            break;
                        case BussConstant.SSTATUS_3:
                            sstatusName = "已下架";
                            break;
                    }
                }
                String xstatusName = "";
                if (null != sstatus) {
                    switch (xstatus.intValue()) {
                        case BussConstant.XSTATUS_1:
                            xstatusName = "下载中";
                            break;
                        case BussConstant.XSTATUS_2:
                            xstatusName = "下载成功";
                            break;
                        case BussConstant.XSTATUS_3:
                            xstatusName = "下载失败";
                            break;
                    }
                }
                sbLog.append(btypeName).append(";").append(fname).append(";")
                        .append(lpath).append(";").append(durl).append(";")
                        .append(createTime).append(";").append(endTime).append(";")
                        .append(finishTime).append(";").append(sstatusName).append(";")
                        .append(xstatusName);

            }
        }
        pars.put("logType", "2"); //下载日志
        pars.put("content", sbLog.toString());

        postMachineLog(pars);
    }


    private void postMachineLog(final Map<String, String> pars) {
        String url = getUrl() + UrlConstantAPI.SAVE_MACHINE_LOG;
        final String serverUrl = url;
        HttpUtil.post(serverUrl, pars, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                LogUtil.i(TAG, "postMachineLog.onFailure..." + e.getMessage());
                String msg = e.getMessage();
                outFalure(msg,serverUrl);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String logType = pars.get("logType");
                String logTypeName = "机器";
                if (logType.equals("2")) {
                    logTypeName = "下载";
                }
                Log.d(TAG, logTypeName + "日志数据报送成功!");

            }
        });
    }

    public void getAD() {
        String url = getUrl() + UrlConstantAPI.GET_AD;
        final String server_url = url;
        final Map<String, String> params = getPars();
        writeLogRecord("getAD Started ...");
        writeLogRecord(url);
        Callback cb = new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                    String errMsg =  "getAD.onFailure..." + e.getMessage();
                Log.i(TAG, errMsg);
                writeLogRecord(errMsg);
                String msg = e.getMessage();
                outFalure(msg,server_url);
                if (null != msg && msg.length() > 255) { //防止长度超标，造成数据保存报错
                    int startIndex = msg.length() - 255;
                    msg = msg.substring(startIndex, msg.length());
                }

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                checkExpireTmpFile();
                String msg = "getAD.onResponse...";
                Log.i(TAG,msg);
                writeLogRecord(msg);
                String resultStr = response.body().string();
                Log.i(TAG, resultStr);
                writeLogRecord(resultStr);

                DownloadLogResult downloadLogResult = JsonHelper.getData(resultStr, DownloadLogResult.class);
                outSuccess(downloadLogResult,server_url);
                if(null == downloadLogResult){
                    msg = "getAD.onResponse downloadLogResult is null";
                    Log.e(TAG,msg);
                    writeLogRecord(msg);
                    return;
                }
                Boolean success = downloadLogResult.getSuccess();
                if (null == downloadLogResult || null == success || !success) return;
                executeScommand(downloadLogResult);
            }
        };

        HttpUtil.post(url, params, cb);
        writeLogRecord("getAD END ...");
    }

    private void executeScommand(DownloadLogResult downloadLogResult) {
        int stype = BussConstant.SCOMMAND_1;
        if(null != downloadLogResult.getStype()){
            stype = downloadLogResult.getStype();
        }

        /*广告上架下架轮询处理方法
         * 服务器只返回上架的广告
         *
         * 处理新上架的，还没下载或者下载失败，开启下载
         * 下载中的暂时忽略
         * 处理本地正在播放，过期或者服务端主动下架的
         * */

        switch (stype) {
            case BussConstant.SCOMMAND_1: {
                Log.i(TAG,"执行心跳...");
               // removeMedia(downloadLogDao.getAllSourceIds());
                break;
            }
            case BussConstant.SCOMMAND_2: {//2:期刊下载
                downLoadMedia(downloadLogResult);
                break;
            }
            case BussConstant.SCOMMAND_3: {//3:下架期刊
                String sourceIds = downloadLogResult.getDelSourceIds();
                removeMedia(sourceIds);
                break;
            }
            case BussConstant.SCOMMAND_4: {//4:报送日志
                //parseMachineLog(downloadLogResult);
                break;
            }
            case BussConstant.SCOMMAND_5: {//5:重启系统
                reboot();
                break;
            }
            case BussConstant.SCOMMAND_6: {//6:APP升级
                break;
            }case BussConstant.SCOMMAND_7: //播放记录报送
                Log.i(TAG,"播放记录报送");
                break;
            case BussConstant.SCOMMAND_8://截图文件报送
                Log.i(TAG, "截图文件报送");
                break;
            case BussConstant.SCOMMAND_9://议峰智播日志报送
                Log.i(TAG,"议峰智播日志报送");
                break;
            case BussConstant.SCOMMAND_10://议峰光传日志报送
                Log.i(TAG,"议峰光传日志报送");
                break;
        }


    }

    /**
     * 检查临时广告文件
     * 用于处理当下载的到机器的广告文件还是.tmp 结尾时，如果这类文件超过广告轮询间隔时间*4倍还没有转为正式下载广告文件时。
     * 将此类文件删除，并从机器重新下载
     */
    private void checkExpireTmpFile(){
        String adPath = machineCacheInfo.getAdPath();
        Integer minutes = machineCacheInfo.getMinutes();
        if(null == minutes || minutes.intValue() == 0) minutes = 5; //默认5分钟
        Integer expireMinutes = 5 * 4;
        final long intervalTime = expireMinutes * 60 * 1000;
        File adDirFile = new File(adPath);
        if(!adDirFile.exists()){
            Log.e(TAG,String.format("机器广告目录：%s不存在！", adPath));
            return;
        }
       File[] tempFiles = adDirFile.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                String fileName = pathname.getName();
                long lastModified = pathname.lastModified();
//                String lastModifiedStr = DateUtil.changTimeMillisToStr(lastModified);
//                Log.i(TAG, String.format("lastModified=%s", lastModifiedStr));
                long expireTime = lastModified+intervalTime;
//                lastModifiedStr = DateUtil.changTimeMillisToStr(expireTime);
//                String currDateStr = DateUtil.changTimeMillisToStr(System.currentTimeMillis());
               // Log.i(TAG, String.format("lastModified2=%s, currDateStr=%s", lastModifiedStr, currDateStr));
                boolean isExpire = false;
                if(expireTime < System.currentTimeMillis()){ //过期临时文件
                    isExpire = true;
                }
                return (null != fileName && fileName.endsWith(".tmp") && isExpire);
            }
       });
       if(null == tempFiles || tempFiles.length == 0){ //没有需要检测的临时文件
           return;
       }
        for(File tempFile : tempFiles){
            String filePath = tempFile.getAbsolutePath();
            boolean isDelete = tempFile.delete();
            Log.i(TAG, String.format("超过%d分钟的临时文件:%s 删除 %s！",expireMinutes, filePath,(isDelete ? "成功" : "失败")));
        }
    }

    /**
     * 系统重启
     */
    private void reboot(){
        //点击的时候发送一条广播出去
        Intent intent = new Intent("com.amlogic.projector.lightswitch");
        mContext.sendBroadcast(intent);
        Toast.makeText(mContext, "系统重启通知发送完成", Toast.LENGTH_SHORT).show();
    }

    /*定期检查期刊过期*/
    private void checkADExpired() {

        List<DownloadLogEntity> expired_list = downloadLogDao.getADExpired();

        if (!expired_list.isEmpty() && expired_list.size() > 0) {
            int delay = 1000;
            for (final DownloadLogEntity downloadLogObj : expired_list) {
                String lpath = downloadLogObj.getLpath();
                if(StringUtils.isEmpty(lpath)) continue;
                File sourceFile = new File(lpath);
                if(!sourceFile.exists()){ //文件不存在时，删除此广告对应的日志
                    downloadLogDao.delete(downloadLogObj.getSourceId());
                    continue;
                }

                delay += 1000;
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        removeMediaByItem(downloadLogObj);

                    }
                }, delay);
            }
            loadLocalFilesToJsonFile();
        }
    }


    /**
     * 下架期刊
     *
     * @param sourceIds
     */
    private void removeMedia(String sourceIds) {
        if (!StringHandler.isValidStr(sourceIds)) return;
        String[] sourceIdArr = sourceIds.split(",");
        StringBuilder sbDelSourceId = new StringBuilder();
        List<String> delFileNameList = new ArrayList<>(sourceIdArr.length);
        for(String sourceId : sourceIdArr){
            String[] arrStr = sourceId.split("_");
            String realSourceId = arrStr[2];
            sbDelSourceId.append(realSourceId).append(",");
            String fileName = String.format("%s_%s",arrStr[0], arrStr[1]);
            delFileNameList.add(fileName);
        }
        delMachieFiles(delFileNameList);
        notifyADAction(ACTION_AD_ADDED,null, BussConstant.CMD_AD_DEL);
        final String delSourceIds = StringHandler.RemoveStr(sbDelSourceId);
        List<DownloadLogEntity> list = downloadLogDao.getListBySourceIds(delSourceIds);
        if (null == list || list.isEmpty()) return;
        delDownLoagLogs(list);
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                updateSourceStatus(delSourceIds, BussConstant.SSTATUS_3);

            }
        }, 1000);
        loadLocalFilesToJsonFile();
    }


    private void delDownLoagLogs(List<DownloadLogEntity> list) {
        for (final DownloadLogEntity downloadLogObj : list) {
            downloadLogObj.setSstatus(BussConstant.SSTATUS_3);
            StringBuilder sbRemark = new StringBuilder();
            String delTime = DateUtil.getCurrentDateTime();
            sbRemark.append("系统收到下架期刊命令，于[" + delTime + "]删除了本机期刊");
            Log.d(TAG, sbRemark.toString());
            downloadLogObj.setRemark(sbRemark.toString());
            downloadLogDao.update(downloadLogObj);
        }
    }

    private void delMachieFiles(List<String> delFileNameList) {
        String adPath = machineCacheInfo.getAdPath();
        final String[] fileNameList = FileUtil.getFileNameList(adPath);
        if(null == fileNameList || fileNameList.length == 0) return;
        for(String machine_fileName : fileNameList){
            for(String delFileName : delFileNameList){
                if(!machine_fileName.startsWith(delFileName)) continue;
                String absFilePath = adPath + machine_fileName;
                Log.i(TAG,  String.format("Del File = %s",absFilePath));
                FileUtil.delete(absFilePath);
                Log.i(TAG,  String.format("%s is Deleted...",absFilePath));
            }
        }

    }

    void removeMediaByItem(DownloadLogEntity downloadLogObj) {
        String lpath = downloadLogObj.getLpath();
        if (StringUtils.isEmpty(lpath)) {
            return;
        }

        File file = new File(lpath);

        if (file.exists()) {
            boolean isDel = FileUtil.delete(lpath);
        }

        if (!file.exists()) {
            downloadLogObj.setSstatus(BussConstant.SSTATUS_3);

//            Intent intent_ad_downloaded = new Intent(ACTION_AD_REMOVED);
//            intent_ad_downloaded.putExtra("ad", downloadLogObj);
//            sendBroadcast(intent_ad_downloaded);

        }
        //ACTION_AD_REMOVED
        notifyADAction(ACTION_AD_ADDED,downloadLogObj, BussConstant.CMD_AD_DEL);

        StringBuilder sbRemark = new StringBuilder();
        String delTime = DateUtil.getCurrentDateTime();
        sbRemark.append("系统收到下架期刊命令，于[" + delTime + "]删除了本机期刊");
        Log.d(TAG, sbRemark.toString());
        downloadLogObj.setRemark(sbRemark.toString());
        downloadLogDao.update(downloadLogObj);
        Long sourceId = downloadLogObj.getSourceId();
        updateSourceStatus(sourceId.toString(), BussConstant.SSTATUS_3);
        loadLocalFilesToJsonFile();
    }

    private static Map<String,DownloadLogEntity> workPool = new LinkedHashMap<>();

    /**
     * 设置要下载的工作池
     * @param list
     */
    private void setWorkPool(List<DownloadLogEntity> list){
        if (null == list || list.isEmpty()) return;
        if(null != workPool && workPool.size() > 0){
            Log.e(TAG,String.format("下载工作池中还有[%d]个广告资源未完成，暂不接收下载任务列表!", workPool.size()));
            return;
        }
        for(DownloadLogEntity downloadLog : list){
            String sourceFileName = downloadLog.getSourceFileName();
            if(workPool.containsKey(sourceFileName)){
                String _surl = downloadLog.getSurl(); //可能存在后台编辑重新替换了新广告视频的情况
                DownloadLogEntity entity = workPool.get(sourceFileName);
                String surl = entity.getSurl();
                if(!StringUtils.isEmpty(_surl) && !_surl.equals(surl)){
                    entity.setSurl(_surl);
                }
                continue;
            }
            downloadLog.setXstatus(BussConstant.XSTATUS_0);
            downloadLog.setReceiveTime(new Date());
            workPool.put(sourceFileName, downloadLog);
        }
    }

    /**
     * 当前正在下载的任务
     */
    static DownloadLogEntity currDownloadLog = null;
    static long currDownLoadLogStartTime = 0;
    /**
     * 获取一个新的下载任务
     * @return
     */
    private DownloadLogEntity takeDownLoadLog(){
        if(null == workPool || workPool.size() == 0) return null;
        Set<String> keys = workPool.keySet();
        String pullKey = null;
        for(String key : keys){
            pullKey = key;
            break;
        }
        return workPool.get(pullKey);
    }

    /**
     * 下载媒体资源
     */
    private void  downLoadMedia(DownloadLogResult downloadLogResult) {
        if(null != currDownloadLog){
            //如果下载时间超过20分钟，就将当前正在下载的缓存记录移除
            long currDateTime = new Date().getTime();
            Log.i(TAG,String.format("currDownLoadLogStartTime=%s,currDateTime=%s, miuntes=%d",
                    DateUtil.changTimeMillisToStr(currDownLoadLogStartTime),DateUtil.changTimeMillisToStr(currDateTime), (currDateTime-currDownLoadLogStartTime)));
            if(currDownLoadLogStartTime > 0 && currDateTime - currDownLoadLogStartTime >= TIMEOUT){
                Log.e(TAG, String.format("当前正在下载广告资源：%s, 下载地址：%s, 已超时%d分钟被清除。系统将再次下载资源!",currDownloadLog.getSourceFileName(), currDownloadLog.getSurl(), MINUTES));
                clearFinishDownLoadLog();
            }else{
                Log.e(TAG, String.format("当前正在下载广告资源：%s, 下载地址：%s",currDownloadLog.getSourceFileName(), currDownloadLog.getSurl()));
                if(isSameStrSource()){ //当为文本广告下载时，如果本地存在相同内容的广告。就从工作池中删除此广告
                    clearFinishDownLoadLog();
                }
                return;
            }
        }
        List<DownloadLogEntity> list = downloadLogResult.getList();
        setWorkPool(list);

        if(null == currDownloadLog){
            currDownloadLog = takeDownLoadLog();
            currDownLoadLogStartTime = new Date().getTime();
        }
        if(null == currDownloadLog){
            Log.e(TAG, String.format("广告资源池中的没有需要下载的资源..."));
            return;
        }
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if(null == currDownloadLog){
                    Log.e(TAG, String.format("currDownloadLog 为空!"));
                    clearFinishDownLoadLog();
                    return;
                }
                startDownLoad(currDownloadLog);
            }
        }, 500);
    }

    private boolean isSameStrSource(){
        String sourceFileName = currDownloadLog.getSourceFileName();
        String content = currDownloadLog.getSurl();
        String adPath = getAdPath();
        String filePath = adPath + sourceFileName;
        File txtFile = new File(filePath);
        if(!txtFile.exists() && !StringUtils.isEmpty(content)){
            FileUtil.writeToFile(txtFile, content,false);
            return true;
        }
        if(StringUtils.isEmpty(content)){
            txtFile.delete();
            return true;
        }
        String localFileContent = FileUtil.readFile(txtFile);
        if(StringUtils.isEmpty(localFileContent)) return false;
        return content.equals(localFileContent);
    }

    private String getAdPath(){
        String adPath = machineCacheInfo.getAdPath();
        if(StringUtils.isEmpty(adPath)) adPath = BussConstant.DEFAULT_ADPATH;
        return adPath;
    }



    /**
     * 校验最新下载记录与本地历史中的下载记录中的广告下载地址是否相同
     * 如果不相同，哪怕本地已经存在下载过的广告文件，也要重新下载变更后的最新广告文件
     * @param item
     * @return
     */
    private boolean checkDownLoadUrlIsSame(DownloadLogEntity item){
        String sourceFileName = item.getSourceFileName();
        DownloadLogEntity localEntity = downloadLogDao.getBySourceName(sourceFileName);
        if(null == localEntity) return true;
        String _surl = localEntity.getSurl();
        if(StringUtils.isEmpty(_surl)) return true;
        String surl = item.getSurl();
        return (surl.equals(_surl));
    }

    /**
     * 素材下载
     *
     * @param item 下载记录
     */
    private void startDownLoad(DownloadLogEntity item) {
        final Long sourceId = item.getSourceId();
        String endTime = item.getEndTime();
        final String surl = item.getSurl();
        String sourceFileName = item.getSourceFileName();
        String aname = item.getAname();
        Long fileSize = item.getFileSize();
        if(null == fileSize) fileSize = 0L;
        String fileMd5 = item.getFileMd5();
        String adPath = machineCacheInfo.getAdPath();
        String address = item.getAddress();
        DownloadLogEntity _downloadLog = downloadLogDao.getBySourceId(sourceId);

        if (null == _downloadLog) {
            _downloadLog = new DownloadLogEntity();
        } else {
            String filePath = machineCacheInfo.getAdPath()+sourceFileName;
            File currAdFile = new File(filePath);
            if(checkDownLoadUrlIsSame(item) && currAdFile.exists()){
                Log.i(TAG,String.format("[%s] 在终端已存在，对应在终端的文件路径：%s", sourceFileName, filePath));
                return;
            }
        }

        final DownloadLogEntity downloadLog = _downloadLog;
        //Cmw Add At: 2020-07-24 18:05 Start
        downloadLog.setFileMd5(fileMd5);
        //Cmw Add At: 2020-07-01 10:57 Start
        downloadLog.setAname(aname);
        downloadLog.setFileSize(fileSize);
        //Cmw Add At: 2020-07-01 10:57 End
        downloadLog.setSourceFileName(sourceFileName);
        downloadLog.setXstatus(BussConstant.XSTATUS_1);
        downloadLog.setSstatus(BussConstant.SSTATUS_1);
        downloadLog.setEndTime(endTime);
        downloadLog.setCreateTime(DateUtil.getCurrentDateTime());
        downloadLog.setDurl(surl);
        downloadLog.setAddress(address);

        if (null == downloadLog.getSourceId()) {
            downloadLog.setSourceId(sourceId);
            downloadLog.setBtype(BussConstant.BTYPE_1);
            downloadLogDao.save(downloadLog);
        } else {
            downloadLogDao.update(downloadLog);
        }

        if(StringHandler.isValidStr(sourceFileName) && sourceFileName.endsWith(".txt")){
            String txtFileName = adPath+sourceFileName;
            File file = new File(txtFileName);
            String lpath = file.getAbsolutePath();
            FileUtil.writeToFile(file,surl,false);
            Log.i(TAG, "广告文本文件创建成功，路径："+lpath);
            updateDownLog(file, lpath, downloadLog, sourceId);
            return;
        }
        if(StringUtils.isEmpty(surl)){
            Log.e(TAG,String.format("广告文件:%s, sourceFileName:%s 对应的下载地址：surl 为空!",sourceFileName,aname));
            return;
        }
        downloadAdSource(surl, downloadLog);
    }

    private void downloadAdSource(final String surl, final DownloadLogEntity downloadLog) {
        DownloadUtil util = DownloadUtil.get();
        String adPath = machineCacheInfo.getAdPath();
        final Long sourceId = downloadLog.getSourceId();
        final String sourceFileName = downloadLog.getSourceFileName();
        util.download(surl, adPath, sourceFileName+ TEMP_FILE_PREFIX, new DownloadUtil.OnDownloadListener() {
            @Override
            public void onDownloadSuccess(File file) {
                clearFinishDownLoadLog();
                String lpath = file.getAbsolutePath();
                Log.i(TAG,String.format("下载完成后的临时文件：%s", lpath));
                lpath = lpath.replace(TEMP_FILE_PREFIX,"");
                File newFile = new File(lpath);
                file.renameTo(newFile);
                String fileMd5 = downloadLog.getFileMd5();
                if(!StringUtils.isEmpty(fileMd5) && isWholeFile(fileMd5, newFile)){
                    Log.i(TAG,String.format("从服务器地址：%s 下载广告成功。广告路径：%s", surl, lpath));
                    updateDownLog(file, lpath, downloadLog, sourceId);
                }else{
                    Log.e(TAG,String.format(String.format("从服务器地址：%s 下载到本地的广告文件：%s ，MD5值不相同，文件未下载完整。将删除重新下载", surl, lpath)));
                    boolean isDelete = newFile.delete();
                    Log.e(TAG,String.format("文件:%s删除%s", lpath,(isDelete ? "成功" : "失败")));
                }
            }

            @Override
            public void onDownloading(int progress) {
                Log.i(TAG,String.format("downloading 百分之 %s ...", progress+""));
            }

            @Override
            public void onDownloadFailed(String errMsg) {
                clearFinishDownLoadLog();
                downloadLog.setXstatus(BussConstant.XSTATUS_3);
                downloadLog.setRemark(errMsg);
                downloadLogDao.update(downloadLog);
                if(null != currDownloadLog){ //如果下载失败，就删除失败文件。并清空当前下载的任务日志对象
                    String sourceFileName = currDownloadLog.getSourceFileName();
                    String filePath = machineCacheInfo.getAdPath()+sourceFileName;
                    FileUtil.delete(filePath);
                    currDownloadLog = null;
                }
                loadLocalFilesToJsonFile();
            }
        });
    }

    private boolean isWholeFile(String serverFileMd5, File localFile){
        boolean isWhole = false;
        String localFileMd5 = com.base.common.util.file.FileUtil.getFileMD5(localFile);
        Log.i(TAG,String.format("文件：%s,服务器上的fileMd5:%s, 本地下载后的fileMd5:%s", localFile.getAbsolutePath(), serverFileMd5, localFileMd5));
        if(StringUtils.isNotEmpty(localFileMd5) && localFileMd5.equals(serverFileMd5)){
            isWhole = true;
        }
        return isWhole;
    }

    private void updateDownLog(File file, String lpath, final DownloadLogEntity downloadLog, final Long sourceId) {
        downloadLog.setFname(file.getName());
        downloadLog.setLpath(lpath);
        downloadLog.setXstatus(BussConstant.XSTATUS_2);
        downloadLog.setSstatus(BussConstant.SSTATUS_2);
        downloadLog.setFinishTime(DateUtil.getCurrentDateTime());
        downloadLogDao.update(downloadLog);

        handler.post(new Runnable() {
            @Override
            public void run() {
                updateSourceStatus(sourceId.toString(), BussConstant.SSTATUS_2);
            }
        });
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                notifyADAction(BussConstant.ACTION_AD_ADDED,downloadLog, BussConstant.CMD_AD_ADD);

            }
        },1000);
        loadLocalFilesToJsonFile();
    }

    private void clearFinishDownLoadLog(){
        if(null != currDownloadLog){
            String sourceFileName = currDownloadLog.getSourceFileName();
            workPool.remove(sourceFileName);
            Log.i(TAG, String.format("从下载工作池中移除了下载成功能文件%s！", sourceFileName));
        }
        currDownloadLog = null;
        currDownLoadLogStartTime = 0;
    }

    void notifyDoorAction(String action) {
        //可以考虑远程下载apk安装，再启动
        Intent player_service = new Intent(action);
        player_service.setComponent(new ComponentName("com.media.yiti.ytplayer","com.media.yiti.ytplayer.service.TaskService"));
        mContext.startService(player_service);
    }

    public void notifyADAction(final int cmd){
        List<DownloadLogEntity> list = downloadLogDao.getListAll();
        final DownloadLogEntity downloadLog = (null != list && list.size() > 0) ? list.get(0) : null;
        final String action = (cmd == BussConstant.CMD_AD_ADD) ? BussConstant.ACTION_AD_ADDED : BussConstant.ACTION_AD_REMOVED;
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                notifyADAction(action,downloadLog, cmd);

            }
        },1000);
    }

    void notifyADAction(String action,DownloadLogEntity downloadLogEntity, int cmd) {
        try{
            String adPath = "";
            if(null != downloadLogEntity) adPath = downloadLogEntity.getLpath();
            Log.i(TAG,String.format("notifyADAction,action=%s, cmd=%s, adPath = %s", action, cmd+"", adPath));
            //可以考虑远程下载apk安装，再启动
            Intent player_broadcast = new Intent(action);
            if(null != downloadLogEntity) player_broadcast.putExtra("ad", downloadLogEntity);
            mContext.sendBroadcast(player_broadcast);
        }catch (Exception ex){
            Log.e(TAG, ex.getMessage());
            ex.printStackTrace();
        }
    }

    public interface ConfirmCallback{
        void execute(AppVersionResult appVersionResult);
    }

    /**
     * 议峰光传APK文件名
     */
    private static final String APK_NAME =  "YF-Sps.apk";

    private static final String APK_NAME_PLAYER = "YF-Player.apk";

    private static final String PACKAGE_PLAYER = "com.media.yiti.ytplayer";

    private boolean isSelfUpdate = true;

    public void checkUpdate(boolean isSelfUpdate,final ConfirmCallback callback){
        this.isSelfUpdate = isSelfUpdate;
        String _version = null;
        String _packageName = null;
        if(this.isSelfUpdate){
            long versionCode = AppTools.getVersionCode(mContext);
            _version = versionCode+"";
            _packageName =  mContext.getPackageName();
        }else{
            _version = getPlayerVersion();
            _packageName = PACKAGE_PLAYER;
        }

        final String version = _version;
        final String packageName = _packageName;
        Log.e(TAG, "versionCode="+version+", packageName="+packageName);

        final Map<String, String> params = new HashMap<String, String>();
        params.put("version", version);
        params.put("packageName",packageName);

        Callback cb = new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.i(TAG, "checkUpdate.onFailure..." + e.getMessage());
                String msg = e.getMessage();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String resultStr = response.body().string();
                JSONObject jsonResult = FastJsonUtil.convertStrToJSONObj(resultStr);
                Boolean success = jsonResult.getBoolean("success");
                String msg = jsonResult.getString("msg");
                if(!success){
                    ToastAlert.showMsg(msg);
                    Log.e(TAG, msg);
                    return;
                }
                JSONObject dataJson = jsonResult.getJSONObject("datas");
                AppVersionResult appVersionResult = JsonHelper.getData(dataJson.toJSONString(), AppVersionResult.class);
                appVersionResult.setOldVersionNum(version);
                appVersionResult.setPackageName(packageName);
                Log.i(TAG,"checkUpdate.onResponse...");
                if(null != callback){
                    callback.execute(appVersionResult);
                }
            }
        };
        String url = getUrl() + UrlConstantAPI.CHECK_APP_VERSION;
        HttpUtil.get(url, params, cb);
    }

    @NonNull
    public String getPlayerVersion() {
        String _version;Context playerContext = null;
        try {
            playerContext = mContext.createPackageContext(PACKAGE_PLAYER,Context.CONTEXT_IGNORE_SECURITY);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        long player_version = AppTools.getVersionCode(playerContext);
        _version = player_version + "";
        return _version;
    }


    public void downloadAPK(AppVersionResult appVersionResult,final Handler handler) {
        DownloadUtil util = DownloadUtil.get();
        Integer utype = appVersionResult.getUtype();  //更新方式 1:静默更新,2:手动更新
        String appPath = appVersionResult.getAppPath();
        String _savePath = null;
       //final String savePath = "/mnt/sdcard/com.yf.cmw/";
       String apkName = null;
       if(this.isSelfUpdate){
           apkName = APK_NAME;
           _savePath = EnvironmentShare.APK + "/";
       }else{
           apkName = APK_NAME_PLAYER;
           _savePath = EnvironmentShare.getSdCardAbsolutePath() + File.separator + PACKAGE_PLAYER+File.separator + "apk";;
       }
       final String savePath = _savePath;
        util.download(appPath, savePath, apkName, new DownloadUtil.OnDownloadListener() {
            @Override
            public void onDownloadSuccess(File file) {
                installOrNotifyPlayer(file, savePath);
            }

            @Override
            public void onDownloading(int progress) {
                Log.e(TAG, String.format("议峰光传下载进度：%d", progress));
                Message message = new Message();
                message.what = BussConstant.HANDLER_APK_DOWNLOAD_PROGRESS;
                message.arg1 = progress;
                handler.sendMessage(message);
            }

            @Override
            public void onDownloadFailed(String errMsg) {
                Log.e(TAG, String.format("议峰光传下载失败：%s", errMsg));
            }
        });
    }

    private void installOrNotifyPlayer(File file, String savePath){
        if(this.isSelfUpdate){
            installAndOpen(file, savePath);
        }else{
            Intent player_install_broadcast = new Intent(BussConstant.ACTION_APK_INSTALL);
            player_install_broadcast.putExtra("apk_file", file);
            player_install_broadcast.putExtra("savePath", savePath);
            mContext.sendBroadcast(player_install_broadcast);
        }
    }

    void installAndOpen(File file, String savePath) {

        ShellUtils.execCommand("chmod 777 " + savePath, false);

        String filePath = file.getAbsolutePath();
        if (!StringUtils.isEmpty(savePath)) {

            CommonUtil.updateAPK(mContext, filePath);
            ToastAlert.showMsg("议峰光传APP更新成功!");
//            if (filePath.endsWith(".apk")) {
//                CommonUtil.installApk(filePath);
//            } else {
//                CommonUtil.openFile(mContext, filePath);
//
//            }
        }
    }

    public void openApp(String packageName,String cmd) {
        try {
            Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(packageName);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra("cmd",cmd);
            mContext.startActivity(intent);
        } catch (Exception e) {

        }
    }

    private Map<String, String> getPars() {
        Map<String, String> params = getBasePars();
        String sourceIds = getFileNameToIds();
        if (null == sourceIds) sourceIds = "";
        params.put("sourceIds", sourceIds); //期刊ID
        return params;
    }

    private String getFileNameToIds(){
        String adPath = machineCacheInfo.getAdPath();
        String[] fileNameList = FileUtil.getFileNameList(adPath);
        if(null == fileNameList || fileNameList.length == 0) return null;
        List<String> tmpFileList = new ArrayList<>();
        for(String fileName : fileNameList){
            if(fileName.endsWith(".tmp")){
                tmpFileList.add(fileName);
                continue;
            }
        }
        if(null != tmpFileList && tmpFileList.size() > 0) {
           boolean deleted = checkAndExpireFiles(tmpFileList);
           if(deleted){
               fileNameList = FileUtil.getFileNameList(adPath);
               if(null == fileNameList || fileNameList.length == 0) return null;
           }
        }
        return StringHandler.join(fileNameList);
    }

    /**
     * 检测如果有临时文件超过30分钟未下载完成。则移除此文件并重新下载
     * @param tmpFileList
     */
    private boolean checkAndExpireFiles(List<String> tmpFileList){
        boolean deleted = false;
        String adPath = machineCacheInfo.getAdPath();
        for(String tmpFileName : tmpFileList){
            File tmpFile = new File(adPath + tmpFileName);
            if(!tmpFile.exists()) continue;
            long lastModified = tmpFile.lastModified();
            //超时30分钟以上的临时文件清理掉，以便重新下载
            long creatTimeOut = (long)(TIMEOUT * 1.5);
            if(lastModified > 0 && System.currentTimeMillis() - lastModified > creatTimeOut){
               deleted = tmpFile.delete();
               Log.e(TAG,String.format("广告文件:%s超过%d分钟未下载完成。系统自动移除并重新下载此文件！",tmpFile.getAbsolutePath(),creatTimeOut));
            }
        }
        return deleted;
    }

    @NonNull
    private Map<String, String> getBasePars() {
        Map<String, String> params = new HashMap<>();
        params.put("mcode", machineCacheInfo.getMcode()); //机器码
        params.put("appVersion", machineCacheInfo.getAppVersion());//APP 版本号
        params.put("appType","1"); //[1:议峰秒传, 2:议峰播放器]
        return params;
    }

    /**
     * 加载本地文件到JSON文件
     */
    synchronized public void loadLocalFilesToJsonFile() {
        FileOutputStream fileOutputStream = null;
        try{
            String homeDir = machineCacheInfo.getAdPath();
            File machineAdDirs = new File(homeDir);
            if(!machineAdDirs.exists()){
                Log.e(TAG,String.format("广告目录：%s不存在，无法加载本地文件到JSON文件",homeDir));
                return;
            }
            final String[] machineFilePaths = machineAdDirs.list();
            JSONArray localFiles = new JSONArray();
            for (String path : machineFilePaths) {
                File file = new File(machineCacheInfo.getAdPath() + path);
                String fileName = file.getName();
                final String fileType = fileName.substring(fileName.lastIndexOf("_") + 1, fileName.lastIndexOf("."));
                String journalName = fileName,
                        createTime = com.base.common.util.file.FileUtil.getFileLastModifiedTime(file, "yyyy-MM-dd HH:mm"),
                        printSize = com.base.common.util.file.FileUtil.getPrintSize(file.length());
                if((BussConstant.FILE_TYPE_1 + "").equals(fileType)){
                    DownloadLogEntity downloadLogEntity = downloadLogDao.getBySourceName(fileName);
                    if(null != downloadLogEntity){
                        journalName = downloadLogEntity.getAname();
                        createTime = downloadLogEntity.getCreateTime();
                    }
                }
                JSONObject fileItem = new JSONObject();
                fileItem.put("journalName", rsaEncode(journalName));
                fileItem.put("fileName", rsaEncode(fileName));
                fileItem.put("createTime", createTime);
                fileItem.put("printSize", printSize);
                localFiles.add(fileItem);
            }
            String jsonFileDir = BussConstant.DEFAULT_CONFIGPATH;
            String jsonFileName = "localFiles.json";
            File jsonFile = new File(jsonFileDir + jsonFileName);
            jsonFile.getParentFile().mkdirs();
            fileOutputStream = new FileOutputStream(jsonFile);
            byte[] bytes = localFiles.toString().getBytes();
            for(int i = 0; i<bytes.length; i++){
                fileOutputStream.write(bytes[i]);
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }finally {
            try{
                if(fileOutputStream != null){
                    fileOutputStream.flush();
                    fileOutputStream.close();
                }
            }catch (Exception ex){
                ex.printStackTrace();
            }
        }
    }

    private String rsaEncode(String str) throws Exception{
        if(!StringHandler.isValidStr(str)) return str;
        byte[] encode = RsaUtils.encryptByPublicKey(str.getBytes(), publicKey);
        return HexUtils.bytesToHexString(encode);
    }

    /**
     * Http业务处理
     * @Author Mr.Shaw
     * @Date 2020/8/9 21:57
     */
    private HttpBusinessCallback httpBusinessCallback = new HttpBusinessCallback() {

        @Override
        public Object handler(String path) {
            return new HttpBusinessHandler(path).start();
        }

        /**
         * Java反射动态触发业务
         * @Author Mr.Shaw
         * @Date 2020/8/9 22:08
         */
        class HttpBusinessHandler{
            String url;
            String formType;
            public HttpBusinessHandler(String path){
                String param_type = StringHandler.getUrlParam(path, "formType");
                this.url = path;
                this.formType = param_type;
            }
            public Object start(){
                try{
                    String method = String.format("form_%s", formType);
                    return HttpBusinessHandler.class.getMethod(method).invoke(this);
                }catch (Exception ex){
                    ex.printStackTrace();
                    return null;
                }
            }
            /**
             * 获取机器所有【已下载、正在上刊】的文件
             * @Author Mr.Shaw
             * @Date 2020/8/9 21:40
             */
            public Object form_10001(){
                List<DownloadLogEntity> downloadLogEntities = downloadLogDao.getADLiveAndDownloaded();
                return JSONArray.parseArray(JSONArray.toJSONString(downloadLogEntities));
            }
            /**
             * 删除期刊
             * @Author Mr.Shaw
             * @Date 2020/8/9 22:21
             */
            public Object form_10002(){
                String sourceId = StringHandler.getUrlParam(this.url, "sourceId");
                if(!StringHandler.isValidStr(sourceId)) return false;
                removeMedia(sourceId);
                return true;
            }
            /**
             * 获取日志列表
             * @Author Mr.Shaw
             * @Date 2020/8/10 21:13
             */
            public Object form_10003(){
                JSONArray logs = new JSONArray();
                String logDirPath = getLogFir(this.url);
                //-- 日志开始时间 - 结束时间
                String startTime = StringHandler.getUrlParam(this.url, "startTime");
                String endTime = StringHandler.getUrlParam(this.url, "endTime");
                Date startDate = dateFormatYMD(startTime);
                Date endDate = dateFormatYMD(endTime);
                File logDir = new File(logDirPath);
                if(logDir.exists()){
                    File[] logFiles = logDir.listFiles();
                    for (File logFile : logFiles) {
                        final String name = logFile.getName();
                        //-- Check the conditions
                        String logTime = name.replaceAll("^android_crash_pad_|.txt", "");
                        Date logDate = dateFormatYMD(logTime);
                        boolean compare1 = dateCompareSize(startDate, logDate),
                        compare2 = dateCompareSize(logDate, endDate);
                        if(!compare1 || !compare2) continue;
                        final String size = com.base.common.util.file.FileUtil.getPrintSize(logFile.length()),
                            createTime = com.base.common.util.file.FileUtil.getFileLastModifiedTime(logFile, "yyyy-MM-dd HH:mm");
                        logs.add(new JSONObject(){{
                            put("name", name);
                            put("size", size);
                            put("createTime", createTime);
                        }});
                    }
                }
                return logs;
            }
            /**
             * 删除日志
             * @Author Mr.Shaw
             * @Date 2020/8/23 23:23
             */
            public Object form_10004(){
                String logDirPath = getLogFir(this.url),
                    fileName = StringHandler.getUrlParam(this.url, "fileName"),
                    filePath = logDirPath + fileName;
                if(!StringHandler.isValidStr(fileName)) return false;
                File file = new File(filePath);
                if(!file.exists()) return false;
                file.delete();
                return true;
            }
        }

        /**
         * 字符串日期转换为yyyy-MM-dd格式的类型
         * @Author Mr.Shaw
         * @Date 2020/8/23 18:38
         */
        private Date dateFormatYMD(String string){
            if(!StringHandler.isValidStr(string)) return null;
            return com.base.common.util.DateUtil.dateFormat(string);
        }

        /**
         * date1是否比date2小, true: 是的, false: 不是
         * @Author Mr.Shaw
         * @Date 2020/8/23 18:37
         */
        private boolean dateCompareSize(Date date1, Date date2){
            if(date1 == null || date2 == null) return true;
            return date1.getTime() <= date2.getTime();
        }

        /**
         * 获取日志目录
         * @Author Mr.Shaw
         * @Date 2020/8/23 23:25
         */
        private String getLogFir(String url){
            //-- 日志类型 [1: 光传(default), 2: 智播]
            String logType = StringHandler.getUrlParam(url, "logType");
            String logDirPath;
            switch(logType){
                default:
                case "1":{
                    logDirPath = BussConstant.LOG_ADPATH;
                    break;
                }
                case "2":{
                    logDirPath = BussConstant.DEFAULT_PLAYER_ADLOG;
                    break;
                }
            }
            return logDirPath;
        }
    };
}
